//! Comprehensive tests for all step types
//!
//! This module tests the complete implementation of all step types
//! to ensure HttpRunner compatibility and functionality.

use ai_test_platform::{
    dsl::DSLProcessor,
    models::{
        config::StepConfig,
        step::{IStep, StepType},
        request::HttpRequest,
    },
    steps::{
        request::RequestStep,
        transaction::TransactionStep,
        thinktime::ThinkTimeStep,
        websocket::WebSocketStep,
    },
};
use serde_json::json;
use tokio;
use uuid::Uuid;

#[tokio::test]
async fn test_step_types_creation() {
    // Test Request step
    let request = HttpRequest::get("https://api.example.com/users".to_string());
    let request_step = RequestStep::new(StepConfig::default(), request);
    assert_eq!(request_step.step_type(), StepType::Request);

    // Test Transaction steps
    let transaction_start = TransactionStep::start("user_workflow".to_string());
    assert_eq!(transaction_start.step_type(), StepType::Transaction);
    assert!(transaction_start.name().contains("Start"));

    let transaction_end = TransactionStep::end("user_workflow".to_string());
    assert_eq!(transaction_end.step_type(), StepType::Transaction);
    assert!(transaction_end.name().contains("End"));

    // Test ThinkTime step
    let thinktime_step = ThinkTimeStep::fixed(2.5);
    assert_eq!(thinktime_step.step_type(), StepType::ThinkTime);
    assert!(thinktime_step.name().contains("2.5"));

    // Test WebSocket step
    let websocket_step = WebSocketStep::connect(
        "wss://api.example.com/ws".to_string(),
        Some("main_connection".to_string()),
    );
    assert_eq!(websocket_step.step_type(), StepType::WebSocket);
    assert!(websocket_step.name().contains("Connect"));
}

#[tokio::test]
async fn test_step_execution_workflow() {
    let test_case_id = Uuid::new_v4();
    let session_id = Uuid::new_v4();
    let mut context = ai_test_platform::models::step::StepContext::new(test_case_id, session_id);

    // Test ThinkTime step execution
    let thinktime_step = ThinkTimeStep::fixed(0.1); // 100ms for testing
    let start_time = std::time::Instant::now();
    let result = thinktime_step.execute(&mut context).await;
    let elapsed = start_time.elapsed();

    assert!(result.is_ok());
    assert!(elapsed.as_millis() >= 90); // Allow some tolerance

    let step_result = result.unwrap();
    assert!(step_result.success);
    assert!(step_result.elapsed > 0);
}

#[tokio::test]
async fn test_transaction_step_execution() {
    let test_case_id = Uuid::new_v4();
    let session_id = Uuid::new_v4();
    let mut context = ai_test_platform::models::step::StepContext::new(test_case_id, session_id);

    // Test transaction start
    let transaction_start = TransactionStep::start("test_transaction".to_string());
    let result = transaction_start.execute(&mut context).await;

    assert!(result.is_ok());
    let step_result = result.unwrap();
    assert!(step_result.success);

    // Verify transaction was recorded in context
    assert!(context.get_variable("transaction_test_transaction").is_some());

    // Test transaction end
    let transaction_end = TransactionStep::end("test_transaction".to_string());
    let result = transaction_end.execute(&mut context).await;

    assert!(result.is_ok());
    let step_result = result.unwrap();
    assert!(step_result.success);

    // Verify transaction duration was calculated
    assert!(context.get_variable("transaction_result_test_transaction").is_some());
}

#[tokio::test]
async fn test_dsl_with_multiple_step_types() {
    let yaml_content = r#"
config:
  name: "Multi-Step Test"
  base_url: "https://api.example.com"
  variables:
    user_id: 123
    transaction_name: "user_workflow"

teststeps:
  - name: "Start Transaction"
    transaction:
      name: "${transaction_name}"
      type: "start"

  - name: "Think Time"
    thinktime:
      type: "fixed"
      duration: 1.0

  - name: "Get User"
    request:
      method: "GET"
      url: "/users/${user_id}"

  - name: "End Transaction"
    transaction:
      name: "${transaction_name}"
      type: "end"
"#;

    let mut processor = DSLProcessor::new();
    let result = processor.process_yaml(yaml_content);

    assert!(result.is_ok());
    let dsl_result = result.unwrap();

    // Verify test case structure
    assert_eq!(dsl_result.test_case.config.name, "Multi-Step Test");
    assert_eq!(dsl_result.test_case.teststeps.len(), 4);

    // Verify variable resolution
    assert!(dsl_result.metadata.variable_resolutions > 0);

    // Verify step types are correctly identified
    let steps = &dsl_result.test_case.teststeps;
    assert!(steps[0].name.contains("Transaction"));
    assert!(steps[1].name.contains("Think"));
    assert!(steps[2].name.contains("Get User"));
    assert!(steps[3].name.contains("Transaction"));
}

#[tokio::test]
async fn test_websocket_step_configuration() {
    // Test WebSocket connect step
    let connect_step = WebSocketStep::connect(
        "wss://echo.websocket.org".to_string(),
        Some("test_connection".to_string()),
    );

    assert_eq!(connect_step.step_type(), StepType::WebSocket);
    assert!(connect_step.name().contains("Connect"));

    // Test WebSocket send step
    let send_step = WebSocketStep::send(
        json!({"message": "Hello WebSocket"}),
        Some("test_connection".to_string()),
    );

    assert_eq!(send_step.step_type(), StepType::WebSocket);
    assert!(send_step.name().contains("Send"));

    // Test WebSocket receive step
    let receive_step = WebSocketStep::receive(
        Some(json!({"type": "response"})),
        Some("test_connection".to_string()),
    );

    assert_eq!(receive_step.step_type(), StepType::WebSocket);
    assert!(receive_step.name().contains("Receive"));

    // Test WebSocket close step
    let close_step = WebSocketStep::close(Some("test_connection".to_string()));

    assert_eq!(close_step.step_type(), StepType::WebSocket);
    assert!(close_step.name().contains("Close"));
}

#[tokio::test]
async fn test_thinktime_variations() {
    // Test fixed think time
    let fixed_step = ThinkTimeStep::fixed(1.5);
    assert!(fixed_step.name().contains("1.5"));

    // Test random think time
    let random_step = ThinkTimeStep::random(0.5, 2.0);
    assert!(random_step.name().contains("0.5"));
    assert!(random_step.name().contains("2"));

    // Test normal distribution think time
    let normal_step = ThinkTimeStep::normal(1.0, 0.2);
    assert!(normal_step.name().contains("μ=1"));
}
